import 'package:bloc/bloc.dart';
import 'package:built_collection/built_collection.dart';
import 'package:mobile_app.core/core/application/models/app_navigator_page_model.dart';
import 'package:mobile_app.core/core/application/models/app_navigator_transition_info.dart';
import 'package:mobile_app.core/core/domain/utils/with_previous_stream.dart';
import 'package:mobile_app.core/root_navigator/application/models/splash_screen_model.dart';

part 'bloc_state.dart';

class RootNavigatorBloc extends Cubit<RootNavigatorBlocState> {
  RootNavigatorBloc() : super(_getInitialState()) {
    streamWithPrevious = stream.withPrevious;
  }

  late final Stream<(RootNavigatorBlocState, RootNavigatorBlocState?)> streamWithPrevious;

  static RootNavigatorBlocState _getInitialState() {
    final pageModels = BuiltList<AppNavigatorPageModel>([
      SplashScreenModel(),
    ]);

    return RootNavigatorBlocState(
      pageModels: pageModels,
      pageModelToTransitionInfo: BuiltMap(),
    );
  }

  void pushPage({
    required AppNavigatorPageModel pageModel,
    AdditionNavigatorTransitionInfo? transitionInfo,
  }) {
    final pageModels = state.pageModels.rebuild((pageModels) {
      pageModels.add(pageModel);
    });

    const defaultTransitionInfo = AdditionNavigatorTransitionInfo(
      hasAnimation: true,
    );

    final updatedPageModelToTransitionInfo =
        state.pageModelToTransitionInfo.rebuild((pageModelToTransitionInfo) {
      pageModelToTransitionInfo[pageModel] = transitionInfo ?? defaultTransitionInfo;
    });

    emit(state.copyWith(
      pageModels: () => pageModels,
      pageModelToTransitionInfo: () => updatedPageModelToTransitionInfo,
    ));
  }

  void pushPageReplacement({
    required AppNavigatorPageModel pageModel,
    AdditionNavigatorTransitionInfo? transitionInfo,
  }) {
    final activePageModel = state.pageModels.last;

    final pageModels = state.pageModels.rebuild((pageModels) {
      pageModels.add(pageModel);
    });

    const defaultEnteringTransitionInfo = AdditionNavigatorTransitionInfo(
      hasAnimation: true,
    );

    const exitingTransitionInfo = RemovalNavigatorTransitionInfo(
      hasAnimation: false,
    );

    final updatedPageModelToTransitionInfo =
        state.pageModelToTransitionInfo.rebuild((pageModelToTransitionInfo) {
      pageModelToTransitionInfo[pageModel] = transitionInfo ?? defaultEnteringTransitionInfo;
      pageModelToTransitionInfo[activePageModel] = exitingTransitionInfo;
    });

    emit(state.copyWith(
      pageModels: () => pageModels,
      pageModelToTransitionInfo: () => updatedPageModelToTransitionInfo,
    ));
  }

  void closePage({
    required AppNavigatorPageModel pageModel,
    RemovalNavigatorTransitionInfo? transitionInfo,
  }) {
    const defaultTransitionInfo = RemovalNavigatorTransitionInfo(
      hasAnimation: true,
    );

    final updatedPageModelToTransitionInfo =
        state.pageModelToTransitionInfo.rebuild((pageModelToTransitionInfo) {
      pageModelToTransitionInfo[pageModel] = transitionInfo ?? defaultTransitionInfo;
    });

    emit(state.copyWith(
      pageModelToTransitionInfo: () => updatedPageModelToTransitionInfo,
    ));
  }

  void handlePop() {
    if (state.pageModels.length <= 1) {
      return;
    }

    const transitionInfo = RemovalNavigatorTransitionInfo(
      hasAnimation: true,
    );

    final updatedPageModelToTransitionInfo =
        state.pageModelToTransitionInfo.rebuild((pageModelToTransitionInfo) {
      pageModelToTransitionInfo[state.pageModels.last] = transitionInfo;
    });

    emit(state.copyWith(
      pageModelToTransitionInfo: () => updatedPageModelToTransitionInfo,
    ));
  }

  void handlePageAdditionToNavigator({
    required AppNavigatorPageModel pageModel,
  }) {
    final updatedPageModelToTransitionInfo =
        state.pageModelToTransitionInfo.rebuild((pageModelToTransitionInfo) {
      pageModelToTransitionInfo.remove(pageModel);
    });

    emit(state.copyWith(
      pageModelToTransitionInfo: () => updatedPageModelToTransitionInfo,
    ));
  }

  void handlePageRemovalFromNavigator({
    required AppNavigatorPageModel pageModel,
  }) {
    final updatedPageModels = state.pageModels.rebuild((pageModels) {
      pageModels.remove(pageModel);
    });

    final updatedPageModelToTransitionInfo =
        state.pageModelToTransitionInfo.rebuild((pageModelToTransitionInfo) {
      pageModelToTransitionInfo.remove(pageModel);
    });

    emit(state.copyWith(
      pageModels: () => updatedPageModels,
      pageModelToTransitionInfo: () => updatedPageModelToTransitionInfo,
    ));
  }

  void updatePageStack({
    required BuiltMap<AppNavigatorPageModel, AppNavigatorTransitionInfo> pageModelToTransitionInfo,
    BuiltList<AppNavigatorPageModel>? pageModels,
  }) {
    emit(state.copyWith(
      pageModels: () => pageModels ?? state.pageModels,
      pageModelToTransitionInfo: () => pageModelToTransitionInfo,
    ));
  }
}
